package com.dlc.apk.core;

import android.os.SystemClock;

import com.dlc.apk.util.LogPlus;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class ShipmentTaskHandler2 {
    private ArrayBlockingQueue<ShipmentTask> taskQueue = new ArrayBlockingQueue(100);
    private CountDownLatch countDownLatch;

    ShipmentTask lastShipmentTask; //最后成功的任务

    public void put(ShipmentTask shipmentTask) {
        taskQueue.offer(shipmentTask);
    }

    public void handleTask(IShipment shipmentImpl, IShipmentTaskCallback shipmentTaskCallback) {
        new Thread(() -> {
            try {
                while (true) {
                    ShipmentTask shipmentTask = taskQueue.take();
                    if (shipmentTask == null) {
                        return;
                    }
                    if (countDownLatch == null || countDownLatch.getCount() == 0L) {
                        countDownLatch = new CountDownLatch(1);
                    }
                    try {
                        shipmentImpl.startShipment(shipmentTask);
                    } catch (Throwable t) {
                        shipmentTaskCallback.onFailed(shipmentTask, t.getMessage());
                    }
                    long startTime = System.currentTimeMillis();
                    long checkDeviceStatusDuration = 1000 * 7 * 2;
                    int retryStartDeviceTimes = 2;
                    boolean isShipmentSuccess = false;
                    long lastRetryTime = startTime;
                    while (System.currentTimeMillis() - startTime <= checkDeviceStatusDuration) {
                        SystemClock.sleep(100L);
                        boolean isShipmentResultSuccess = shipmentImpl.checkIsShipmentSuccessed(shipmentTask);
                        if (isShipmentResultSuccess) {
                            isShipmentSuccess = true;
                            break;
                        }

                        if (retryStartDeviceTimes > 0 && System.currentTimeMillis() - lastRetryTime >= 1000 * 7) {
                            LogPlus.e("###重试->$shipmentTask");
                            lastRetryTime = System.currentTimeMillis();
                            retryStartDeviceTimes--;
                            shipmentImpl.startShipment(shipmentTask);
                        }
                    }
                    if (isShipmentSuccess) {
                        shipmentTaskCallback.onSuccess(shipmentTask);
                        shipmentTask.shipmentTaskCallback.onSuccess(shipmentTask);
                        //更新"任务"中成功的时间
                        shipmentTask.shipmentTime = System.currentTimeMillis();
                        //任务完成
                        doCompleteTaskAndStartNext();
                    } else {
                        shipmentTaskCallback.onFailed(shipmentTask, "超时未能出货完成");
                        shipmentTask.shipmentTaskCallback.onFailed(shipmentTask, "超时未能出货完成");
                        //任务完成 继续处理下一个任务
                        doCompleteTaskAndStartNext();
                    }
                    //阻塞等待流程任务完成 超过一定时间则强制结束
                    countDownLatch.await(2, TimeUnit.MINUTES);
                    LogPlus.e("###本次任务完成### startDeviceTask->${shipmentTask}");
                    //记录最后任务 后台需要带上订单号上报
                    this.lastShipmentTask = shipmentTask;
                }
            } catch (Throwable e) {
                e.printStackTrace();
                LogPlus.e("处理任务线程异常,${LogPlus.getStackTraceInfo(e)}");
            }
            /*停止处理任务*/
            LogPlus.e("###处理任务线程已停止");
        }).start();
    }

    public void doCompleteTaskAndStartNext() {
        countDownLatch.countDown();
    }

    public static class InstanceHolder {
        private static final ShipmentTaskHandler2 instance = new ShipmentTaskHandler2();
    }

    public static ShipmentTaskHandler2 getInstance() {
        return InstanceHolder.instance;
    }

    public static class ShipmentTask {
        private int flowNo;
        private int cargoNumberType;
        private int actionCargoRowNumberOrNo1;
        private int actionCargoColumnNumber1;
        private int actionCargoRowNumberOrNo2;
        private int actionCargoColumnNumber2;
        private int actionCargoRowNumberOrNo3;
        private int actionCargoColumnNumber3;
        private int actionCargoRowNumberOrNo4;
        private int actionCargoColumnNumber4;
        private int actionCargoRowNumberOrNo5;
        private int actionCargoColumnNumber5;
        private int maxActionTime;
        private int pickTimeOut;
        private int theftBaffleTimeout;
        private Object attachData;
        private long shipmentTime;
        private int errCode;
        private int firstShipmentResult;
        private IShipmentTaskCallback shipmentTaskCallback;

        public ShipmentTask(int flowNo, int cargoNumberType, int actionCargoRowNumberOrNo1, int actionCargoColumnNumber1, int actionCargoRowNumberOrNo2, int actionCargoColumnNumber2, int actionCargoRowNumberOrNo3, int actionCargoColumnNumber3, int actionCargoRowNumberOrNo4, int actionCargoColumnNumber4, int actionCargoRowNumberOrNo5, int actionCargoColumnNumber5, int maxActionTime, int pickTimeOut, int theftBaffleTimeout, Object attachData, long shipmentTime, int errCode, int firstShipmentResult, IShipmentTaskCallback shipmentTaskCallback) {
            this.flowNo = flowNo;
            this.cargoNumberType = cargoNumberType;
            this.actionCargoRowNumberOrNo1 = actionCargoRowNumberOrNo1;
            this.actionCargoColumnNumber1 = actionCargoColumnNumber1;
            this.actionCargoRowNumberOrNo2 = actionCargoRowNumberOrNo2;
            this.actionCargoColumnNumber2 = actionCargoColumnNumber2;
            this.actionCargoRowNumberOrNo3 = actionCargoRowNumberOrNo3;
            this.actionCargoColumnNumber3 = actionCargoColumnNumber3;
            this.actionCargoRowNumberOrNo4 = actionCargoRowNumberOrNo4;
            this.actionCargoColumnNumber4 = actionCargoColumnNumber4;
            this.actionCargoRowNumberOrNo5 = actionCargoRowNumberOrNo5;
            this.actionCargoColumnNumber5 = actionCargoColumnNumber5;
            this.maxActionTime = maxActionTime;
            this.pickTimeOut = pickTimeOut;
            this.theftBaffleTimeout = theftBaffleTimeout;
            this.attachData = attachData;
            this.shipmentTime = shipmentTime;
            this.errCode = errCode;
            this.firstShipmentResult = firstShipmentResult;
            this.shipmentTaskCallback = shipmentTaskCallback;
        }

        public int getFlowNo() {
            return flowNo;
        }

        public void setFlowNo(int flowNo) {
            this.flowNo = flowNo;
        }

        public int getCargoNumberType() {
            return cargoNumberType;
        }

        public void setCargoNumberType(int cargoNumberType) {
            this.cargoNumberType = cargoNumberType;
        }

        public int getActionCargoRowNumberOrNo1() {
            return actionCargoRowNumberOrNo1;
        }

        public void setActionCargoRowNumberOrNo1(int actionCargoRowNumberOrNo1) {
            this.actionCargoRowNumberOrNo1 = actionCargoRowNumberOrNo1;
        }

        public int getActionCargoColumnNumber1() {
            return actionCargoColumnNumber1;
        }

        public void setActionCargoColumnNumber1(int actionCargoColumnNumber1) {
            this.actionCargoColumnNumber1 = actionCargoColumnNumber1;
        }

        public int getActionCargoRowNumberOrNo2() {
            return actionCargoRowNumberOrNo2;
        }

        public void setActionCargoRowNumberOrNo2(int actionCargoRowNumberOrNo2) {
            this.actionCargoRowNumberOrNo2 = actionCargoRowNumberOrNo2;
        }

        public int getActionCargoColumnNumber2() {
            return actionCargoColumnNumber2;
        }

        public void setActionCargoColumnNumber2(int actionCargoColumnNumber2) {
            this.actionCargoColumnNumber2 = actionCargoColumnNumber2;
        }

        public int getActionCargoRowNumberOrNo3() {
            return actionCargoRowNumberOrNo3;
        }

        public void setActionCargoRowNumberOrNo3(int actionCargoRowNumberOrNo3) {
            this.actionCargoRowNumberOrNo3 = actionCargoRowNumberOrNo3;
        }

        public int getActionCargoColumnNumber3() {
            return actionCargoColumnNumber3;
        }

        public void setActionCargoColumnNumber3(int actionCargoColumnNumber3) {
            this.actionCargoColumnNumber3 = actionCargoColumnNumber3;
        }

        public int getActionCargoRowNumberOrNo4() {
            return actionCargoRowNumberOrNo4;
        }

        public void setActionCargoRowNumberOrNo4(int actionCargoRowNumberOrNo4) {
            this.actionCargoRowNumberOrNo4 = actionCargoRowNumberOrNo4;
        }

        public int getActionCargoColumnNumber4() {
            return actionCargoColumnNumber4;
        }

        public void setActionCargoColumnNumber4(int actionCargoColumnNumber4) {
            this.actionCargoColumnNumber4 = actionCargoColumnNumber4;
        }

        public int getActionCargoRowNumberOrNo5() {
            return actionCargoRowNumberOrNo5;
        }

        public void setActionCargoRowNumberOrNo5(int actionCargoRowNumberOrNo5) {
            this.actionCargoRowNumberOrNo5 = actionCargoRowNumberOrNo5;
        }

        public int getActionCargoColumnNumber5() {
            return actionCargoColumnNumber5;
        }

        public void setActionCargoColumnNumber5(int actionCargoColumnNumber5) {
            this.actionCargoColumnNumber5 = actionCargoColumnNumber5;
        }

        public int getMaxActionTime() {
            return maxActionTime;
        }

        public void setMaxActionTime(int maxActionTime) {
            this.maxActionTime = maxActionTime;
        }

        public int getPickTimeOut() {
            return pickTimeOut;
        }

        public void setPickTimeOut(int pickTimeOut) {
            this.pickTimeOut = pickTimeOut;
        }

        public int getTheftBaffleTimeout() {
            return theftBaffleTimeout;
        }

        public void setTheftBaffleTimeout(int theftBaffleTimeout) {
            this.theftBaffleTimeout = theftBaffleTimeout;
        }

        public Object getAttachData() {
            return attachData;
        }

        public void setAttachData(Object attachData) {
            this.attachData = attachData;
        }

        public long getShipmentTime() {
            return shipmentTime;
        }

        public void setShipmentTime(long shipmentTime) {
            this.shipmentTime = shipmentTime;
        }

        public int getErrCode() {
            return errCode;
        }

        public void setErrCode(int errCode) {
            this.errCode = errCode;
        }

        public int getFirstShipmentResult() {
            return firstShipmentResult;
        }

        public void setFirstShipmentResult(int firstShipmentResult) {
            this.firstShipmentResult = firstShipmentResult;
        }

        public IShipmentTaskCallback getShipmentTaskCallback() {
            return shipmentTaskCallback;
        }

        public void setShipmentTaskCallback(IShipmentTaskCallback shipmentTaskCallback) {
            this.shipmentTaskCallback = shipmentTaskCallback;
        }
    }

    interface IShipmentTaskCallback {
        void onSuccess(ShipmentTask shipmentTask);

        void onFailed(ShipmentTask shipmentTask, String msg);
    }

    interface IShipment {
        /*发送出货命令*/
        void startShipment(ShipmentTask shipmentTask);

        /*检查是否已出货*/
        boolean checkIsShipmentSuccessed(ShipmentTask shipmentTask);
    }
}
